﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UtcDateTime.cs" company="">
//   
// </copyright>
// <summary>
//   The utc date time.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Core
{
    using System;

    /// <summary>
    ///   The utc date time.
    /// </summary>
    public struct UtcDateTime
    {
        #region Fields

        /// <summary>
        ///   The m_date time.
        /// </summary>
        private DateTime m_dateTime;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UtcDateTime"/> struct.
        /// </summary>
        /// <param name="dateTime">
        /// The date time. 
        /// </param>
        public UtcDateTime(DateTime dateTime)
        {
            this.m_dateTime = dateTime.ToUniversalTime();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UtcDateTime"/> struct.
        /// </summary>
        /// <param name="ticks">
        /// The ticks. 
        /// </param>
        public UtcDateTime(long ticks)
        {
            this.m_dateTime = new DateTime(ticks);
            this.m_dateTime = DateTime.SpecifyKind(this.m_dateTime, DateTimeKind.Utc);
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets the max value.
        /// </summary>
        public static UtcDateTime MaxValue
        {
            get
            {
                return new UtcDateTime(DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc));
            }
        }

        /// <summary>
        ///   Gets the min value.
        /// </summary>
        public static UtcDateTime MinValue
        {
            get
            {
                return new UtcDateTime(DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc));
            }
        }

        /// <summary>
        ///   Gets the now.
        /// </summary>
        public static UtcDateTime Now
        {
            get
            {
                return new UtcDateTime(DateTime.UtcNow);
            }
        }

        /// <summary>
        ///   Gets the ticks.
        /// </summary>
        public long Ticks
        {
            get
            {
                return this.m_dateTime.Ticks;
            }
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the date time.
        /// </summary>
        internal DateTime DateTime
        {
            get
            {
                return this.m_dateTime;
            }

            set
            {
                this.m_dateTime = value;
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The equals.
        /// </summary>
        /// <param name="d1">
        /// The d 1. 
        /// </param>
        /// <param name="d2">
        /// The d 2. 
        /// </param>
        /// <returns>
        /// The <see cref="bool"/> . 
        /// </returns>
        public static bool Equals(UtcDateTime d1, UtcDateTime d2)
        {
            return d1.Equals(d2);
        }

        /// <summary>
        /// The from binary.
        /// </summary>
        /// <param name="val">
        /// The val. 
        /// </param>
        /// <returns>
        /// The <see cref="UtcDateTime"/> . 
        /// </returns>
        public static UtcDateTime FromBinary(long val)
        {
            return new UtcDateTime(DateTime.SpecifyKind(DateTime.FromBinary(val), DateTimeKind.Utc));
        }

        /// <summary>
        /// The parse.
        /// </summary>
        /// <param name="str">
        /// The str. 
        /// </param>
        /// <param name="formatProvider">
        /// The format provider. 
        /// </param>
        /// <returns>
        /// The <see cref="UtcDateTime"/> . 
        /// </returns>
        public static UtcDateTime Parse(string str, IFormatProvider formatProvider)
        {
            return new UtcDateTime(DateTime.SpecifyKind(DateTime.Parse(str, formatProvider), DateTimeKind.Utc));
        }

        /// <summary>
        ///   The +.
        /// </summary>
        /// <param name="d"> The d. </param>
        /// <param name="t"> The t. </param>
        /// <returns> </returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static UtcDateTime operator +(UtcDateTime d, TimeSpan t)
        {
            long ticks = d.DateTime.Ticks;
            long num2 = t.Ticks;
            if ((num2 > (0x2bca2875f4373fff - ticks)) || (num2 < -ticks))
            {
                throw new ArgumentOutOfRangeException("t", "Overflow_DateArithmetic");
            }

            return new UtcDateTime(ticks + num2);
        }

        /// <summary>
        ///   The ==.
        /// </summary>
        /// <param name="d1"> The d 1. </param>
        /// <param name="d2"> The d 2. </param>
        /// <returns> </returns>
        public static Boolean operator ==(UtcDateTime d1, UtcDateTime d2)
        {
            return Equals(d1, d2);
        }

        /// <summary>
        ///   The &gt;.
        /// </summary>
        /// <param name="d1"> The d 1. </param>
        /// <param name="d2"> The d 2. </param>
        /// <returns> </returns>
        public static Boolean operator >(UtcDateTime d1, UtcDateTime d2)
        {
            return d1.DateTime.Ticks > d2.DateTime.Ticks;
        }

        /// <summary>
        ///   The &gt;=.
        /// </summary>
        /// <param name="d1"> The d 1. </param>
        /// <param name="d2"> The d 2. </param>
        /// <returns> </returns>
        public static Boolean operator >=(UtcDateTime d1, UtcDateTime d2)
        {
            return d1.DateTime.Ticks >= d2.DateTime.Ticks;
        }

        /// <summary>
        ///   The !=.
        /// </summary>
        /// <param name="d1"> The d 1. </param>
        /// <param name="d2"> The d 2. </param>
        /// <returns> </returns>
        public static Boolean operator !=(UtcDateTime d1, UtcDateTime d2)
        {
            return d1.DateTime.Ticks != d2.DateTime.Ticks;
        }

        /// <summary>
        ///   The &lt;.
        /// </summary>
        /// <param name="d1"> The d 1. </param>
        /// <param name="d2"> The d 2. </param>
        /// <returns> </returns>
        public static Boolean operator <(UtcDateTime d1, UtcDateTime d2)
        {
            return d1.DateTime.Ticks < d2.DateTime.Ticks;
        }

        /// <summary>
        ///   The &lt;=.
        /// </summary>
        /// <param name="d1"> The d 1. </param>
        /// <param name="d2"> The d 2. </param>
        /// <returns> </returns>
        public static Boolean operator <=(UtcDateTime d1, UtcDateTime d2)
        {
            return d1.DateTime.Ticks <= d2.DateTime.Ticks;
        }

        /// <summary>
        ///   The -.
        /// </summary>
        /// <param name="d1"> The d 1. </param>
        /// <param name="d2"> The d 2. </param>
        /// <returns> </returns>
        public static TimeSpan operator -(UtcDateTime d1, UtcDateTime d2)
        {
            return new TimeSpan(d1.Ticks - d2.Ticks);
        }

        /// <summary>
        ///   The -.
        /// </summary>
        /// <param name="d"> The d. </param>
        /// <param name="t"> The t. </param>
        /// <returns> </returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static UtcDateTime operator -(UtcDateTime d, TimeSpan t)
        {
            long ticks = d.Ticks;
            long num2 = t.Ticks;
            if ((ticks < num2) || ((ticks - 0x2bca2875f4373fff) > num2))
            {
                throw new ArgumentOutOfRangeException("t", "Overflow_DateArithmetic");
            }

            return new UtcDateTime(ticks - num2);
        }

        /// <summary>
        /// The equals.
        /// </summary>
        /// <param name="value">
        /// The value. 
        /// </param>
        /// <returns>
        /// The <see cref="bool"/> . 
        /// </returns>
        public bool Equals(UtcDateTime value)
        {
            return this.DateTime.Ticks == value.DateTime.Ticks;
        }

        /// <summary>
        /// The equals.
        /// </summary>
        /// <param name="value">
        /// The value. 
        /// </param>
        /// <returns>
        /// The <see cref="bool"/> . 
        /// </returns>
        public override bool Equals(object value)
        {
            if (value is UtcDateTime)
            {
                return this.Equals((UtcDateTime)value);
            }

            return false;
        }

        /// <summary>
        ///   The get hash code.
        /// </summary>
        /// <returns> The <see cref="int" /> . </returns>
        public override int GetHashCode()
        {
            return this.m_dateTime.GetHashCode();
        }

        /// <summary>
        ///   The to binary.
        /// </summary>
        /// <returns> The <see cref="long" /> . </returns>
        public long ToBinary()
        {
            return this.DateTime.ToBinary();
        }

        /// <summary>
        /// The to string.
        /// </summary>
        /// <param name="formatProvider">
        /// The format provider. 
        /// </param>
        /// <returns>
        /// The <see cref="string"/> . 
        /// </returns>
        public string ToString(IFormatProvider formatProvider)
        {
            return this.DateTime.ToString(formatProvider);
        }

        #endregion
    }
}